using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using CodePlex.TfsLibrary.ObjectModel;
using CodePlex.TfsLibrary.RepositoryWebSvc;

namespace CodePlex.CodePlexClientLibrary
{
    public partial class StatusListView : UserControl
    {
        string basePath;
        public EventHandler<EventArgs<SourceItem>> ItemAdd;
        public EventHandler<EventArgs<SourceItem>> ItemDelete;
        public EventHandler<EventArgs<SourceItem>> ItemDiff;
        public EventHandler<EventArgs<SourceItem>> ItemDiffMineAgainstBase;
        public EventHandler<EventArgs<SourceItem>> ItemDiffTheirsAgainstBase;
        public EventHandler<EventArgs<SourceItem>> ItemMerge;
        public EventHandler<EventArgs<SourceItem>> ItemResolve;
        public EventHandler<EventArgs<SourceItem>> ItemRevert;
        readonly Dictionary<string, ListViewItem> listViewItems = new Dictionary<string, ListViewItem>(StringComparer.InvariantCultureIgnoreCase);
        readonly Dictionary<SourceItemStatus, ContextMenuStrip> menus = new Dictionary<SourceItemStatus, ContextMenuStrip>();

        public StatusListView()
        {
            InitializeComponent();

            menus.Add(SourceItemStatus.Add, addMenuStrip);
            menus.Add(SourceItemStatus.Conflict, conflictMenuStrip);
            menus.Add(SourceItemStatus.Delete, deleteMenuStrip);
            menus.Add(SourceItemStatus.Missing, missingMenuStrip);
            menus.Add(SourceItemStatus.Modified, modifiedMenuStrip);
            menus.Add(SourceItemStatus.Unmodified, unmodifiedMenuStrip);
            menus.Add(SourceItemStatus.Unversioned, unversionedMenuStrip);
        }

        public string BasePath
        {
            get { return basePath; }
            set { basePath = value; }
        }

        SourceItem SelectedSourceItem
        {
            get
            {
                if (changesetListView.SelectedItems.Count == 0)
                    return null;
                return (changesetListView.SelectedItems[0].Tag as SourceItem);
            }
        }

        void changesetListView_DoubleClick(object sender,
                                           EventArgs e)
        {
            SourceItem item = SelectedSourceItem;

            if (item != null)
            {
                switch (item.LocalItemStatus)
                {
                    case SourceItemStatus.Modified:
                        DoDiff(null, null);
                        break;

                    case SourceItemStatus.Conflict:
                        DoMerge(null, null);
                        break;
                }
            }
        }

        void changesetListView_SelectedIndexChanged(object sender,
                                                    EventArgs e)
        {
            UpdateContextMenu();
        }

        public void DisplayItem(SourceItem item)
        {
            ListViewItem lvi = GetListViewItem(item.LocalName);
            lvi.ForeColor = GetForeColor(item.LocalItemStatus);
            lvi.SubItems[1].Text = item.LocalItemStatus.ToString();
            lvi.Tag = item;

            if (item.ItemType == ItemType.Folder && item.LocalItemStatus == SourceItemStatus.Unversioned)
                RemoveChildren(item.LocalName);

            UpdateItemCount();
            UpdateContextMenu();
        }

        void DoAdd(object sender,
                   EventArgs e)
        {
            if (ItemAdd != null)
                ItemAdd(this, new EventArgs<SourceItem>(SelectedSourceItem));
        }

        void DoDelete(object sender,
                      EventArgs e)
        {
            if (ItemDelete != null)
                ItemDelete(this, new EventArgs<SourceItem>(SelectedSourceItem));
        }

        void DoDiff(object sender,
                    EventArgs e)
        {
            if (ItemDiff != null)
                ItemDiff(this, new EventArgs<SourceItem>(SelectedSourceItem));
        }

        void DoDiffMineAgainstBase(object sender,
                                   EventArgs e)
        {
            if (ItemDiffMineAgainstBase != null)
                ItemDiffMineAgainstBase(this, new EventArgs<SourceItem>(SelectedSourceItem));
        }

        void DoDiffTheirsAgainstBase(object sender,
                                     EventArgs e)
        {
            if (ItemDiffTheirsAgainstBase != null)
                ItemDiffTheirsAgainstBase(this, new EventArgs<SourceItem>(SelectedSourceItem));
        }

        void DoMerge(object sender,
                     EventArgs e)
        {
            if (ItemMerge != null)
                ItemMerge(this, new EventArgs<SourceItem>(SelectedSourceItem));
        }

        void DoResolve(object sender,
                       EventArgs e)
        {
            if (ItemResolve != null)
                ItemResolve(this, new EventArgs<SourceItem>(SelectedSourceItem));
        }

        void DoRevert(object sender,
                      EventArgs e)
        {
            if (ItemRevert != null)
                ItemRevert(this, new EventArgs<SourceItem>(SelectedSourceItem));
        }

        static Color GetForeColor(SourceItemStatus status)
        {
            switch (status)
            {
                case SourceItemStatus.Add:
                    return Color.FromArgb(0x33, 0x99, 0x33);

                case SourceItemStatus.Conflict:
                    return Color.FromArgb(0x99, 0x33, 0x33);

                case SourceItemStatus.Delete:
                    return Color.FromArgb(0x33, 0x99, 0x99);

                case SourceItemStatus.Missing:
                    return Color.FromArgb(0x99, 0x33, 0x99);

                case SourceItemStatus.Unmodified:
                    return Color.FromArgb(0x99, 0x99, 0x99);

                case SourceItemStatus.Unversioned:
                    return Color.FromArgb(0x33, 0x33, 0x99);

                default:
                    return Color.Black;
            }
        }

        ListViewItem GetListViewItem(string localName)
        {
            if (listViewItems.ContainsKey(localName))
                return listViewItems[localName];

            ListViewItem lvi = new ListViewItem(CodePlexClientUtil.GetRelativePath(BasePath, localName));
            lvi.SubItems.Add("");
            listViewItems[localName] = lvi;
            changesetListView.Items.Add(lvi);
            return lvi;
        }

        void RemoveChildren(string localName)
        {
            localName += @"\";
            List<string> toDelete = new List<string>();

            foreach (KeyValuePair<string, ListViewItem> kvp in listViewItems)
            {
                if (kvp.Key.StartsWith(localName))
                {
                    kvp.Value.Remove();
                    toDelete.Add(kvp.Key);
                }
            }

            foreach (string key in toDelete)
                listViewItems.Remove(key);
        }

        public void RemoveItem(string localName)
        {
            ListViewItem lvi = GetListViewItem(localName);

            if (lvi != null)
            {
                lvi.Remove();
                RemoveChildren(localName);
            }

            UpdateItemCount();
        }

        void UpdateContextMenu()
        {
            ContextMenuStrip menu = null;

            if (changesetListView.SelectedItems.Count > 0)
            {
                SourceItem item = (SourceItem)changesetListView.SelectedItems[0].Tag;

                if (menus.ContainsKey(item.LocalItemStatus))
                    menu = menus[item.LocalItemStatus];
            }

            changesetListView.ContextMenuStrip = menu;
        }

        public void UpdateItem(SourceItem item)
        {
            ListViewItem lvi = GetListViewItem(item.LocalName);

            if (lvi != null)
            {
                lvi.Tag = item;
                lvi.Text = CodePlexClientUtil.GetRelativePath(BasePath, item.LocalName);
                lvi.SubItems[1].Text = item.LocalItemStatus.ToString();
                UpdateContextMenu();
            }
        }

        void UpdateItemCount()
        {
            countsLabel.Text = string.Format("{0} item{1}", changesetListView.Items.Count, changesetListView.Items.Count == 1 ? "" : "s");
        }
    }
}